
#include <iostream>
#include <cstdio>
#include <cstdlib>

#include <thread>
#include <mutex>
//#include <list>
#include <queue>

#include "SimpleDHT.h"
#include "pcf8523.h"
#include "PCA9535.h"

#define SERV_PORT 8880
#define CMD_READ "read"
#define CMD_WRITE "write"

#define RES_CODE_INVALIDCMD 100
#define UART_BAUDRATE   115200

#ifdef HOST_ORANGE_PI
#define UART_MAX_NUM    4
#else
#define UART_MAX_NUM    1
#endif

#define APPBOARD_MAX_NUM 9
#define APPBOARD_DEF_ADDR 0xFF

#define PIN_SENSOR_DHT11 4
#define PIN_UART_485D_CTRL 6
#define PIN_PHYKEY_IO_INT 21
#define PIN_BOARD_CHN_INT  1

#define TIMEOUT_485_READ_MS 5000

using namespace std;

class NodeAppBoard
{
public:
	NodeAppBoard();
	~NodeAppBoard();
	NodeAppBoard(const NodeAppBoard& b){};
	NodeAppBoard& operator=(const NodeAppBoard& b){
			if(this != &b)
			{
			mUsed = b.used();
			mAddr = b.addr();
			mModel=b.model();
			mAppID=b.appid();
			mHdver = b.hardver();
			mFwver = b.firmver();
			}

			return *this;
	};

	bool used() const ;
	int addr() const ;
	string model() const ;
	string appid() const ;
	void setBoard(int addr,string model,string id);
	void setBoard(bool use);
	
	string hardver() const {return mHdver;}
	string firmver() const {return mFwver;}

	void setVersion(const char *hdver,const char *fwver)
	{
			mHdver = hdver;
			mFwver = fwver;
			return ;
	}

private:
	bool mUsed;
	int mAddr;
	string mModel;
	string mAppID;
	string mHdver;
	string mFwver;
};

class NodeHost
{
public:
	static NodeHost* getHost();

private:
	static NodeHost* mHost;
	NodeHost();
	NodeHost(string name);
	~NodeHost();

public:

	string name() const {return mName;}
	bool initEnv();

	void startService();

	// Sensors Read
	float readTemprature();
	float readHumidity();
	float readAirpressure();
	float readLuminosity();	

	DateTime getTime();
	void setTime(DateTime& dt);

	// Extended AppBoard Process
	int getAppBoard(NodeAppBoard boards[]);
	bool findAppBoard(int addr);
	void sendMsgToBoard(int addr,string msg);
	bool readMsgFromBoard(string& msg);
	bool eventFromBoard(string& msg);

private:
	int write485(const char *msg);
	int read485(char msg[],int size);
	int read485(string& msg);

	int process_app_request(char *in,int len,char *out,int outlen);
	int process_board_request(char *in,int len,char *out,int outlen);

	void on_insert_board(int chn);
	void on_remove_board(int chn);
	void on_notify_board(int chn);

	void recvAppCmd();
	void sendAppMsg();
	void detectAppBoard();

private:
	string mName;

	SimpleDHT11 mTempHumi;
	float mTemprature;
	float mHumidity;
	float mAirpress;
	float mLuminosity;

	PCF8523 mRtc;
	PCA9535 mIOLedKey;
	PCA9535 mIOChnInt;
	PCA9535 mIOChnDis;
	NodeAppBoard mBoards[APPBOARD_MAX_NUM];

	mutex mBoardLock;
	mutex mMsgLock;

	int mAppFd;

	std::thread mThread[3];// RecvAppCmd,SendBoardEvent,DetectAppBoard(Insert/Remove/Notify)
	std::queue<string> mSndMsgQueue;
	std::queue<string> mToNanoQueue;
	std::queue<string> mFromNanoQueue;

	int m485Fd;
};
